-- local core = require "sproto.core"
local log = require "log";
local sproto = require "sproto";
local sprotoloader = require "sprotoloader";
local netpack = require "us_netpack";

-- 协议池
local proto_pool = {};

-- 会话id
local g_session_id = 0;
local g_cb_list = {};


local us_rpc = {};

-- 注册协议
function us_rpc:register_proto(proto_type, proto)
    if proto_pool[proto_type] then
        log.info("register an exist proto : %s! so we replace it", proto_type);
    end
    proto_pool[proto_type] = proto;
end

-- 获取协议
local function get_proto(proto_type, proto)
    return proto_pool[proto_type];
end

-- 生成response
local function gen_response(_type, tag, session)
    return function(args)
        local msg = {
            proto_type = _type,
            proto_id = tag,
            session_id = session,
            data = args,
        }
		return us_rpc:ecnode_msg(msg)
	end
end

function us_rpc:unpack(pbuffer, sz)
    local packet = netpack.decode(pbuffer, sz);
    if not packet then return end
    local proto_type = packet.head.proto_type;
    -- local proto = get_proto(packet.proto_type);
    local proto = sprotoloader.load(proto_type);
    if not proto then return end

    local tag = packet.head.proto_id
    local content = sproto.unpack(packet.data.buffer);
    local session = packet.head.session_id;

    local msg, proto_name;
    local request_type = packet.head.request_type
    if 2 == request_type then        -- response
        msg = proto:response_decode(tag, content);
        return request_type, g_cb_list[session], msg;
    else                                    -- request
        msg, proto_name = proto:request_decode(tag, content);
        if session > 0 then
            return request_type, proto_name, msg, gen_response(proto_type, tag, session);
        else
            return request_type, proto_name, msg;
        end
    end
    return request_type, proto_name, msg;
end


function us_rpc:pack(msg)
    local proto_type = assert(msg.proto_type, "msg must have a number field 'proto_type' ");
    local data = assert(msg.data, "msg must have a table field 'data' ");

    -- local proto = get_proto(msg.proto_type);
    local proto = sprotoloader.load(proto_type);
    if not proto then return end

    local tag = msg.proto_id
    local buffer;
    if tag and tag > 0 then                 -- response
        buffer = proto:response_encode(tag, data);
        msg.request_type = 2;
        msg.session_id = msg.session_id or 0;
    else                                    -- request
        local proto_name = assert(msg.proto_name, "request msg must have a string field 'proto_name' ");
        local callback = msg.callback;
        buffer, tag = proto:request_encode(proto_name, data);
        if callback and #buffer > 0 then
            g_session_id = g_session_id + 1;
            msg.session_id = g_session_id;
            g_cb_list[g_session_id] = callback;
        else
            msg.session_id = 0;
        end
        msg.request_type = 1;
        msg.proto_id = tag;
    end

    buffer = sproto.pack(buffer);
    return buffer
end

-- ecnode msg
function us_rpc:ecnode_msg(msg)
    local buffer = us_rpc:pack(msg);
    local p = netpack.create(buffer, msg.proto_type, msg.proto_id, msg.encrypt_type, msg.compress_type)
    p.head.request_type = msg.request_type;
    p.head.session_id = msg.session_id;
    return netpack.encode_packet(p);
end

---发送消息
---@param msg table @账号GUID
---@return string @Buffer
function us_rpc.send_request(msg)
    return us_rpc:ecnode_msg(msg)
end

return us_rpc
